import { computed, defineComponent, mergeProps } from 'vue';

import { UiCard, UiDialog, UiDynamicRender, UiEmpty, UiForm, UiPagination, UiRightToolbar, UiTable } from 'ui-widgets';

// #region 组件创建
export default function useCrudNodes({ config, state, componentTracker, refs, actions, slotsProps }) {
  // 创建各个组件模块
  const searchModule = createSearchComps({ config, state, componentTracker, refs, actions, slotsProps });
  const toolbarModule = createToolbarCompts({ config, state, componentTracker, refs, actions, slotsProps });
  const tableModule = createTableCompts({ config, state, componentTracker, refs, actions, slotsProps });
  const paginationModule = createPaginationCompts({ config, state, componentTracker, refs, actions, slotsProps });
  const updateDialogModule = createUpdateDialogCompts({ config, state, componentTracker, refs, actions, slotsProps });

  // 组装组件和属性
  const components = {
    SearchCard: searchModule.components.SearchCardComp,
    SearchForm: searchModule.components.SearchFormComp,
    LeftToolbar: toolbarModule.components.LeftToolbarComp,
    RightToolbar: toolbarModule.components.RightToolbarComp,
    Table: tableModule.components.TableComp,
    TableCard: tableModule.components.TableCardComp,
    TableControls: tableModule.components.TableControlsComp,
    Pagination: paginationModule.components.PaginationComp,
    UpdateDialog: updateDialogModule.components.UpdateDialogComp,
    UpdateForm: updateDialogModule.components.UpdateFormComp,
    UpdateDialogFooter: updateDialogModule.components.UpdateDialogFooterComp,
  };

  slotsProps.searchCard = searchModule.props.searchCardProps;
  slotsProps.searchForm = searchModule.props.searchFormProps;
  slotsProps.leftToolbar = toolbarModule.props.leftToolbarProps;
  slotsProps.rightToolbar = toolbarModule.props.rightToolbarProps;
  slotsProps.table = tableModule.props.tableProps;
  slotsProps.tableCard = tableModule.props.tableCardProps;
  slotsProps.tableControls = tableModule.props.tableControlsProps;
  slotsProps.pagination = paginationModule.props.paginationProps;
  slotsProps.updateDialog = updateDialogModule.props.updateDialogProps;
  slotsProps.updateForm = updateDialogModule.props.updateFormProps;
  slotsProps.updateDialogFooter = updateDialogModule.props.updateDialogFooterProps;

  return [components];
}

function createVNode(Comp, options = {}, slotsComp = {}, componentTracker, componentName, callback) {
  const exposeProps = ref(options);

  const CompVNode = defineComponent((props, { attrs, slots }) => {
    componentTracker.markComponentUsed(componentName);
    onUnmounted(() => {
      componentTracker.removeComponent(componentName);
    });
    const newProps = reactive(mergeProps(options, props, attrs));
    exposeProps.value = newProps;

    let defineSlots = {
      ...slotsComp,
      ...slots,
    };

    if (callback && typeof callback === 'function') {
      // result打算用于处理props，slots
      const result = callback(newProps, slots);
      if (result && result.slots) defineSlots = result.slots;
    }

    return () => h(Comp, newProps, defineSlots);
  });

  return [CompVNode, exposeProps];
}
// #endregion

// #region 搜索组件创建
function createSearchComps({ config, state, componentTracker, refs, actions }) {
  const [SearchCardComp, searchCardProps] = createVNode(
    UiCard,
    {
      style: {
        display: computed(() => (state.showSearch ? 'block' : 'none')),
      },
      bodyPadding: '20px 20px 2px',
      ref: (val) => (refs.searchCard = val),
    },
    {},
    componentTracker,
    'SearchCard',
  );

  // 查询表单
  const [SearchFormComp, searchFormProps] = createVNode(
    UiForm,
    {
      search: true,
      labelWidth: '100px',
      onSubmit: actions.onSearch,
      onSearch: actions.onSearch,
      onReset: actions.onResetSearch,
      ref: (val) => (refs.searchForm = val),
    },
    {},
    componentTracker,
    'SearchForm',
    (props, slots) => {
      // 这里不能使用deepClone, 因为克隆效果不知道为啥会失效（表单数据变化，克隆数据也会变化）
      state.cloneSearchModel = JSON.parse(JSON.stringify(props.model));
    },
  );

  return {
    components: { SearchCardComp, SearchFormComp },
    props: { searchCardProps, searchFormProps },
  };
}
// #endregion

// #region 工具栏组件创建
function createToolbarCompts({ config, state, componentTracker, refs, actions }) {
  const [LeftToolbarComp, leftToolbarProps] = createVNode(
    UiDynamicRender,
    {
      options: computed(() => state.leftToolbarOptions),
      ref: (val) => (refs.leftToolbar = val),
    },
    {},
    componentTracker,
    'LeftToolbar',
  );

  const [RightToolbarComp, rightToolbarProps] = createVNode(
    UiRightToolbar,
    {
      showSearch: computed(() => state.showSearch),
      'onUpdate:showSearch': (val) => (state.showSearch = val),
      columns: computed(() => state.columns),
      onQueryTable: actions.onSearch,
      style: { marginLeft: 'auto' },
      ref: (val) => (refs.rightToolbar = val),
    },
    {},
    componentTracker,
    'RightToolbar',
  );

  return {
    components: { LeftToolbarComp, RightToolbarComp },
    props: { leftToolbarProps, rightToolbarProps },
  };
}
// #endregion

// #region 表格组件创建
function createTableCompts({ config, state, componentTracker, refs, actions, slotsProps }) {
  // 表格
  const [TableComp, tableProps] = createVNode(
    UiTable,
    {
      options: computed(() => state.tableOptions),
      data: computed(() => state.data),
      'onUpdate:data': (val) => (state.data = val),
      style: 'flex: 1',
      'show-overflow-tooltip': true,
      ref: (val) => (refs.table = val),
      onSelectionChange: actions.onSelectionChange,
    },
    {
      empty: () => h(UiEmpty, { msg: '暂无数据' }),
    },
    componentTracker,
    'Table',
  );

  // 表格卡片
  const [TableCardComp, tableCardProps] = createVNode(
    UiCard,
    {
      flex: true,
      ref: (val) => (refs.tableCard = val),
    },
    {},
    componentTracker,
    'TableCard',
  );

  const [TableControlsComp, tableControlsProps] = createVNode(
    UiDynamicRender,
    {
      options: computed(() => state.tableControlsOptions),
      ref: (val) => (refs.tableControls = val),
    },
    {},
    componentTracker,
    'TableControls',
  );

  return {
    components: { TableComp, TableCardComp, TableControlsComp },
    props: { tableProps, tableCardProps, tableControlsProps },
  };
}
// #endregion

// #region 分页组件创建
function createPaginationCompts({ config, state, componentTracker, refs, actions }) {
  const [PaginationComp, paginationProps] = createVNode(
    UiPagination,
    {
      total: 0,
      page: computed(() => state.page),
      'onUpdate:page': (val) => {
        state.page = val;
      },
      limit: computed(() => state.limit),
      'onUpdate:limit': (val) => {
        state.limit = val;
      },
      style: { padding: '0' },
      onPagination: actions.onPagination,
      ref: (val) => (refs.pagination = val),
    },
    {},
    componentTracker,
    'Pagination',
  );

  return {
    components: { PaginationComp },
    props: { paginationProps },
  };
}
// #endregion

// #region 编辑弹窗组件创建
function createUpdateDialogCompts({ config, state, componentTracker, refs, actions }) {
  const [UpdateDialogComp, updateDialogProps] = createVNode(
    UiDialog,
    {
      title: computed(() => (state.isEdit ? '修改' : '新增')),
      alignCenter: true,
      modelValue: computed(() => state.visible),
      'onUpdate:modelValue': (val) => (state.visible = val),
      ref: (val) => (refs.updateDialog = val),
      onClosed: actions.onClosed,
    },
    {},
    componentTracker,
    'UpdateDialog',
  );

  const [UpdateFormComp, updateFormProps] = createVNode(
    UiForm,
    {
      labelWidth: '100px',
      model: computed(() => state.updateFormModel),
      options: computed(() => state.updateFormOptions),
      ref: (val) => (refs.updateForm = val),
    },
    {},
    componentTracker,
    'UpdateForm',
    (props) => {
      // 这里不能使用deepClone, 因为克隆效果不知道为啥会失效（表单数据变化，克隆数据也会变化）
      state.cloneUpdateModel = JSON.parse(JSON.stringify(props.model));
    },
  );

  const [UpdateDialogFooterComp, updateDialogFooterProps] = createVNode(
    UiDynamicRender,
    {
      options: computed(() => state.updateDialogFooterOptions),
      ref: (val) => (refs.updateDialogFooter = val),
    },
    {},
    componentTracker,
    'UpdateDialogFooter',
  );

  return {
    components: { UpdateDialogComp, UpdateFormComp, UpdateDialogFooterComp },
    props: { updateDialogProps, updateFormProps, updateDialogFooterProps },
  };
}
// #endregion

// #region 公共方法
function deepClone(source) {
  if (!source || !Array.isArray(source) || validType(source, 'Object')) return source;

  const targetObj = source.constructor === Array ? [] : {};
  Object.keys(source).forEach((keys) => {
    targetObj[keys] = source[keys] && typeof source[keys] === 'object' ? deepClone(source[keys]) : source[keys];
  });
  return targetObj;
}

// 判断类型
function validType(value, type) {
  return Object.prototype.toString.call(value) === `[object ${type}]`;
}
// #endregion